package org.abratuhi.kvngroupware.pubsub;

import java.util.ArrayList;

import org.abratuhi.kvngroupware.pubsub.Publication;
import org.abratuhi.kvngroupware.pubsub.Subscription;

public class HubNode {
	String attribute;
	Value minimum;
	Value maximum;
	ArrayList<Subscription> subscriptions = new ArrayList<Subscription>();
	
	public HubNode(String attribute, Value value, Value value2){
		this.attribute = attribute;
		this.minimum = value;
		this.maximum = value2;
	}
	
	public static  HubNode[] split(HubNode hn){
		HubNode hn1 = new HubNode(hn.attribute, hn.minimum, hn.minimum.midTo(hn.maximum));
		HubNode hn2 = new HubNode(hn.attribute, hn.minimum.midTo(hn.maximum), hn.maximum);
		
		for(int i=0; i<hn.subscriptions.size(); i++){
			if((hn.subscriptions.get(i)).intersects(hn1.attribute, hn1.minimum, hn1.maximum)) hn1.addSubscription(hn.subscriptions.get(i));
			if((hn.subscriptions.get(i)).intersects(hn2.attribute, hn2.minimum, hn2.maximum)) hn2.addSubscription(hn.subscriptions.get(i));
		}
		
		System.out.println("SPLIT:");
		System.out.println("Was:");
		System.out.println(hn.toString());
		System.out.println("Now:");
		System.out.println(hn1.toString());
		System.out.println(hn2.toString());
		
		return new HubNode[]{hn1, hn2};
	}
	
	public static HubNode[] balanceToLeft(HubNode hnOverloaded, HubNode hnHelper){
		HubNode nhnHelper = new HubNode(hnHelper.attribute, hnHelper.minimum, hnHelper.maximum.midTo(hnOverloaded.maximum));
		HubNode nhnOverloaded = new HubNode(hnOverloaded.attribute, hnHelper.maximum.midTo(hnOverloaded.maximum), hnOverloaded.maximum);
		nhnHelper.subscriptions.addAll(hnHelper.subscriptions);
		for(int i=0; i<hnOverloaded.subscriptions.size(); i++){
			if(hnOverloaded.subscriptions.get(i).intersects(hnOverloaded.attribute, nhnOverloaded.minimum, nhnOverloaded.maximum)) nhnOverloaded.addSubscription(hnOverloaded.subscriptions.get(i));
			if(hnOverloaded.subscriptions.get(i).intersects(hnOverloaded.attribute, nhnHelper.minimum, nhnHelper.maximum)) nhnHelper.addSubscription(hnOverloaded.subscriptions.get(i));
		}
		System.out.println("LBALANCING:");
		System.out.println("Was:");
		System.out.println(hnOverloaded.toString());
		System.out.println(hnHelper.toString());
		System.out.println("NOW:");
		System.out.println(nhnOverloaded.toString());
		System.out.println(nhnHelper.toString());
		return new HubNode[]{nhnOverloaded, nhnHelper};
	}
	
	public static HubNode[] balanceToRight(HubNode hnOverloaded, HubNode hnHelper){
		HubNode nhnOverloaded = new HubNode(hnOverloaded.attribute, hnOverloaded.minimum, hnOverloaded.minimum.midTo(hnHelper.minimum));
		HubNode nhnHelper = new HubNode(hnHelper.attribute, hnOverloaded.minimum.midTo(hnHelper.minimum), hnHelper.maximum);
		for(int i=0; i<hnOverloaded.subscriptions.size(); i++){
			if(hnOverloaded.subscriptions.get(i).intersects(hnOverloaded.attribute, nhnOverloaded.minimum, nhnOverloaded.maximum)) nhnOverloaded.addSubscription(hnOverloaded.subscriptions.get(i));
			if(hnOverloaded.subscriptions.get(i).intersects(hnOverloaded.attribute, nhnHelper.minimum, nhnHelper.maximum)) nhnHelper.addSubscription(hnOverloaded.subscriptions.get(i));
		}
		System.out.println("RBALANCING:");
		System.out.println("Was:");
		System.out.println(hnOverloaded.toString());
		System.out.println(hnHelper.toString());
		System.out.println("NOW:");
		System.out.println(nhnOverloaded.toString());
		System.out.println(nhnHelper.toString());
		nhnHelper.subscriptions.addAll(hnHelper.subscriptions);
		return new HubNode[]{nhnOverloaded, nhnHelper};
	}
	
	public static HubNode merge(HubNode[] hns){
		HubNode hn = new HubNode(hns[0].attribute, hns[0].minimum, hns[hns.length-1].maximum);
		for(HubNode hnn : hns) hn.subscriptions.addAll(hnn.subscriptions);
		return hn;
	}
	
	public void addSubscription(Subscription sub){
		subscriptions.add(sub);
	}
	
	public String toString(){
		String result = new String();
		result += "\thubnode: "+minimum.toString()+" <= "+attribute+"<="+maximum.toString()+"\n";
		for(int i=0; i<subscriptions.size(); i++) result += "\t\t" + subscriptions.get(i).toString()+"\n";
		return result;
	}
	
	public void updateSubscription(){
		//ValueODO
	}
	
	public void removeSubscription(String subscriptionId){
		for(int i=0; i<subscriptions.size(); i++) if(subscriptions.get(i).subscriptionId.equals(subscriptionId)) subscriptions.remove(i);
	}
	
	public void removeSubscriptions(String subscriberId){
		for(int i=0; i<subscriptions.size(); i++) if(subscriptions.get(i).subscriberId.equals(subscriberId)) subscriptions.remove(i);
	}
	
	public Subscription getSubscription(String subscriptionId){
		for(int i=0; i<subscriptions.size(); i++) if(subscriptions.get(i).subscriptionId.equals(subscriptionId)) return subscriptions.get(i);
		return null;
	}
	
	public ArrayList<Subscription> getSubscriptions(String subscriberId){
		ArrayList<Subscription> result = new ArrayList<Subscription>();
		for(int i=0; i<subscriptions.size(); i++) if(subscriptions.get(i).subscriberId.equals(subscriberId)) result.add(subscriptions.get(i));
		return result;
	}
	
	public int indexOfSubscription(String subscriptionId){
		for(int i=0; i<subscriptions.size(); i++) if(subscriptions.get(i).subscriptionId.equals(subscriptionId)) return i;
		return -1;
	}
	
	public ArrayList<Subscription> match(Publication pub){
		ArrayList<Subscription> result = new ArrayList<Subscription>();
		for(int i=0; i<subscriptions.size(); i++){
			if(subscriptions.get(i).matches(pub)){
				result.add(subscriptions.get(i));
			}
		}
		return result;
	}
}
